home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 February / EnigmA AMIGA RUN 15 (1997)(G.R. Edizioni)(IT)[!][issue 1997-02][PLANET CD V].iso / enigma / earcd / utility / utilwb / rndpat.lha / RndPat / RndPat.c < prev    next >
C/C++ Source or Header  |  1996-10-27  |  13KB  |  635 lines

  1. /* RndPat
  2.  *
  3.  * Random Workbench background picture selector.
  4.  *
  5.  * Public domain in 1996 by Magnus Holmgren.
  6.  */
  7.  
  8. #include "RndPat.h"
  9.  
  10.  
  11. /******************** Useful macros ********************/
  12.  
  13.  
  14. #define FOREACHNODE(list,node,next)     \
  15.     for( node = ( APTR ) ( ( ( struct List * ) ( list ) )->lh_Head );       \
  16.         ( next = ( APTR ) ( ( ( struct Node * ) node )->ln_Succ ) );    \
  17.         node = next )
  18. #define MIN(a,b)    ( ( a ) < ( b ) ? ( a ) : ( b ) )
  19.  
  20.  
  21. /******************** Global variables ********************/
  22.  
  23.  
  24. struct DosLibrary    *DOSBase;
  25. struct Library        *IFFParseBase;
  26. struct IntuitionBase    *IntuitionBase;
  27. struct ExecBase        *SysBase;
  28. struct Library        *UtilityBase;
  29.  
  30.  
  31. /******************** Startup code ********************/
  32.  
  33.  
  34. #define CloseLib(l)    CloseLibrary( ( struct Library * ) l )
  35.  
  36. STATIC APTR    OpenLib( const STRPTR, const LONG );
  37. STATIC LONG    Main( VOID );
  38.  
  39.  
  40. SAVEDS LONG
  41. Startup( VOID )
  42. {
  43.     LONG    rc = RETURN_FAIL;
  44.  
  45.     SysBase = *( ( struct ExecBase ** ) 4 );
  46.  
  47.     if( DOSBase = ( struct DosLibrary * ) OpenLibrary( "dos.library", 39 ) )
  48.     {
  49.         if( IntuitionBase = OpenLib( "intuition.library", 39 ) )
  50.         {
  51.             if( UtilityBase = OpenLib( "utility.library", 39 ) )
  52.             {
  53.                 if( IFFParseBase = OpenLib( "iffparse.library", 39 ) )
  54.                 {
  55.                     rc = Main();
  56.  
  57.                     CloseLib( IFFParseBase );
  58.                 } /* if */
  59.  
  60.                 CloseLib( UtilityBase );
  61.             } /* if */
  62.  
  63.             CloseLib( IntuitionBase );
  64.         } /* if */
  65.  
  66.         CloseLib( DOSBase );
  67.     } /* if */
  68.  
  69.     return( rc );
  70. } /* Startup */
  71.  
  72.  
  73. STATIC APTR
  74. OpenLib( const STRPTR name, const LONG version )
  75. {
  76.     APTR    lib;
  77.  
  78.     if( !( lib = OpenLibrary( name, version ) ) )
  79.     {
  80.         Printf( "RndPat: Couldn't open %s version %ld or higher\n", name, version );
  81.     } /* if */
  82.  
  83.     return( lib );
  84. } /* OpenLib */
  85.  
  86.  
  87. const STATIC TEXT Version[] = "$VER: RndPat 1.0 (27.10.96)";
  88.  
  89.  
  90. /******************** Random stuff ********************/
  91.  
  92.  
  93. STATIC ULONG    Seed;
  94.  
  95.  
  96. /* Basically FastRand() in amiga.lib */
  97. STATIC ULONG
  98. Rand( const ULONG limit )
  99. {
  100.     Seed = ( Seed << 1 ) ^ 0x1D872B41;
  101.     return( Seed % limit );
  102. } /* Rand */
  103.  
  104.  
  105. STATIC VOID
  106. InitSeed( VOID )
  107. {
  108.     ULONG    t;
  109.  
  110.     CurrentTime( &Seed, &t );
  111. } /* InitSeed */
  112.  
  113.  
  114. /******************** Random file stuff ********************/
  115.  
  116.  
  117. /* Buffer size for fairly quick drawer scanning,
  118.  * but without excessive memory needs.
  119.  */
  120. #define EXALLBUF 2048
  121.  
  122.  
  123. /* Allocate a node, with name stored in ln_Name.
  124.  * Use FreeVec() to free the node.
  125.  */
  126. STATIC struct Node *
  127. AllocNameNode( const STRPTR name )
  128. {
  129.     struct Node    *node;
  130.  
  131.     if( node = AllocVec( ( ULONG ) ( sizeof( struct Node ) + ( strlen( name ) + 1 ) ), MEMF_ANY ) )
  132.     {
  133.         node->ln_Name = ( STRPTR ) ( node + 1 );
  134.         strcpy( node->ln_Name, name );
  135.     } /* if */
  136.  
  137.     return( node );
  138. } /* AllocNameNode */
  139.  
  140.  
  141. /* Scan the specified dir (only accepting the files that match the parsed
  142.  * pattern, which may be NULL, in which case all files match), and add the
  143.  * resulting file names to the end of list (ln_Name holds the name).
  144.  *
  145.  * Returns number of files found, or -1 for an error. Check IoErr() for
  146.  * reason.
  147.  *
  148.  * To free a node, simply call FreeVec() on it.
  149.  */
  150. STATIC LONG
  151. ScanDir( struct List *list, const STRPTR dir, const STRPTR pattern )
  152. {
  153.     struct ExAllData    *eaData;
  154.     LONG    numFiles = -1;
  155.  
  156.     if( eaData = AllocVec( EXALLBUF, MEMF_PUBLIC | MEMF_CLEAR ) )
  157.     {
  158.         struct ExAllControl *eac;
  159.  
  160.         if( eac = AllocDosObject( DOS_EXALLCONTROL, NULL ) )
  161.         {
  162.             BPTR    lock;
  163.  
  164.             if( lock = Lock( dir, SHARED_LOCK ) )
  165.             {
  166.                 struct Node        *node;
  167.                 struct ExAllData    *ead;
  168.                 BOOL    more;
  169.  
  170.                 numFiles = 0;
  171.                 eac->eac_LastKey = 0;
  172.                 eac->eac_MatchString = pattern;
  173.  
  174.                 do
  175.                 {
  176.                     more = ExAll( lock, eaData, EXALLBUF, ED_TYPE, eac );
  177.  
  178.                     if( !more && ( IoErr() != ERROR_NO_MORE_ENTRIES ) )
  179.                     {
  180.                         break;
  181.                     } /* if */
  182.  
  183.                     if( !eac->eac_Entries )
  184.                     {
  185.                         continue;
  186.                     } /* if */
  187.  
  188.                     numFiles += eac->eac_Entries;
  189.  
  190.                     for( ead = eaData; ead; ead = ead->ed_Next )
  191.                     {
  192.                         /* Ignore any drawers found. It won't
  193.                          * handle soft links, but I don't want to
  194.                          * mess around with that here and now! ;)
  195.                          */
  196.                         if( ead->ed_Type > 0 )
  197.                         {
  198.                             continue;
  199.                         }
  200.                         else if( node = AllocNameNode( ead->ed_Name ) )
  201.                         {
  202.                             AddTail( list, node );
  203.                         }
  204.                         else
  205.                         {
  206.                             /* End processing */
  207.                             ExAllEnd( lock, eaData, EXALLBUF, ED_TYPE, eac );
  208.                             more = FALSE;    /* Break out of loop now */
  209.                             break;
  210.                         } /* if */
  211.                     } /* for */
  212.                 } while( more );
  213.  
  214.                 if( !node )
  215.                 {
  216.                     SetIoErr( ERROR_NO_FREE_STORE );
  217.                 } /* if */
  218.  
  219.                 if( IoErr() != ERROR_NO_MORE_ENTRIES )
  220.                 {
  221.                     numFiles = -1;
  222.                 } /* if */
  223.  
  224.                 UnLock( lock );
  225.             } /* if */
  226.  
  227.             FreeDosObject( DOS_EXALLCONTROL, eac );
  228.         } /* if */
  229.  
  230.         FreeVec( eaData );
  231.     } /* if */
  232.  
  233.     return( numFiles );
  234. } /* ScanDir */
  235.  
  236.  
  237. /* Free a list of AllocVec:ed nodes */
  238. STATIC VOID
  239. FreeList( struct List *list )
  240. {
  241.     struct Node    *node, *next;
  242.  
  243.     FOREACHNODE( list, node, next )
  244.     {
  245.         FreeVec( node );
  246.     } /* FOREACHNODE */
  247.  
  248.     NewList( list );
  249. } /* FreeList */
  250.  
  251.  
  252. /* Assumes name refers to a directory, possibly with a filename part of name
  253.  * that is a pattern. Scans the directory the name and file pattern refers
  254.  * to, and randomly select one of the files. If the name does contain a
  255.  * pattern, it will be removed.
  256.  *
  257.  * Returns a struct Node, with ln_Name set to the file name, or NULL.
  258.  * FreeVec() the node to get rid of it.
  259.  *
  260.  * In case of NULL return, IoErr() contains more information.
  261.  */
  262. STATIC struct Node *
  263. GetRandomFile( STRPTR name )
  264. {
  265.     struct List    fileList;
  266.     struct Node    *rc = NULL;
  267.     STRPTR    pattern, file;
  268.     LONG    i, numFiles;
  269.  
  270.     NewList( &fileList );
  271.     file = FilePart( name );
  272.     i = ( strlen( file ) + 1 ) * 2 * sizeof( TEXT );
  273.  
  274.     if( pattern = AllocVec( i, MEMF_PUBLIC ) )
  275.     {
  276.         if( 1 != ParsePatternNoCase( file, pattern, i ) )
  277.         {
  278.             FreeVec( pattern );
  279.             pattern = NULL;
  280.         }
  281.         else
  282.         {
  283.             /* Remove pattern from directory name */
  284.             *file = '\0';
  285.         } /* if */
  286.     } /* if */
  287.  
  288.     if( ( numFiles = ScanDir( &fileList, name, pattern ) ) > 0 )
  289.     {
  290.         i = Rand( numFiles ) + 1;
  291.         rc = fileList.lh_Head;
  292.  
  293.         while( --i )
  294.         {
  295.             /* Go to the right file */
  296.             rc = rc->ln_Succ;
  297.         } /* while */
  298.  
  299.         Remove( rc );
  300.         FreeList( &fileList );
  301.     } /* if */
  302.  
  303.     FreeVec( pattern );
  304.     return( rc );
  305. } /* GetRandomFile */
  306.  
  307.  
  308. /******************** WBPattern prefs stuff ********************/
  309.  
  310.  
  311. #define IFFERR_NOFILE    IFF_RETURN2CLIENT
  312.  
  313.  
  314. /* Return error string based on input IFF error code. Assumes code to be
  315.  * different from zero, and within range.
  316.  */
  317. STATIC const STRPTR
  318. IffError( const LONG code )
  319. {
  320.     const STATIC STRPTR
  321.     ErrorStrings[] =
  322.     {
  323.         "End of file",
  324.         "End of chunk",
  325.         "No valid scope for property",
  326.         "Not enough memory",
  327.         "Read error",
  328.         "Write error",
  329.         "Seek error",
  330.         "Mangled file",
  331.         "Syntax error",
  332.         "Not an IFF file",
  333.         "No hook provided",
  334.         "Couldn't open file"
  335.     }; /* ErrorStrings */
  336.  
  337.     return( ErrorStrings[ ~code ] );
  338. } /* IffError */
  339.  
  340.  
  341. /* Hm.. Not the best macro perhaps, but... ;) */
  342. #define IFF(x)    if( ( rc = x ) < 0 ) { return( rc ); }
  343.  
  344.  
  345. /* Write the actual prefs data. Returns IFF error code */
  346. STATIC LONG
  347. WriteWBPatternPrefs( struct IFFHandle *iff, STRPTR *patterns, const BOOL remap )
  348. {
  349.     struct PrefHeader    header;
  350.     struct WBPatternPrefs    prefs;
  351.     LONG    rc, i;
  352.  
  353.     /* Clear prefs structs */
  354.     memset( &header, 0, sizeof( header ) );
  355.     memset( &prefs, 0, sizeof( prefs ) );
  356.  
  357.     if( remap )
  358.     {
  359.         prefs.wbp_Flags = WBPF_NOREMAP;
  360.     } /* if */
  361.  
  362.     IFF( OpenIFF( iff, IFFF_WRITE ) );
  363.     IFF( PushChunk( iff, ID_PREF, ID_FORM, IFFSIZE_UNKNOWN ) );
  364.     IFF( PushChunk( iff, ID_PREF, ID_PRHD, sizeof( header ) ) );
  365.     IFF( WriteChunkBytes( iff, &header, sizeof( header ) ) );
  366.     IFF( PopChunk( iff ) );
  367.  
  368.     for( i = WBP_ROOT; i <= WBP_SCREEN; ++i, ++patterns )
  369.     {
  370.         if( *patterns )
  371.         {
  372.             prefs.wbp_Which = i;
  373.             prefs.wbp_DataLength = strlen( *patterns ) + 1;
  374.  
  375.             IFF( PushChunk( iff, ID_PREF, ID_PTRN, ( LONG ) ( sizeof( prefs ) + prefs.wbp_DataLength ) ) );
  376.             IFF( WriteChunkBytes( iff, &prefs, sizeof( prefs ) ) );
  377.             IFF( WriteChunkBytes( iff, *patterns, ( LONG ) prefs.wbp_DataLength ) );
  378.             IFF( PopChunk( iff ) );
  379.         } /* if */
  380.     } /* for */
  381.  
  382.     return( PopChunk( iff ) );
  383. } /* WriteWBPatternPrefs */
  384.  
  385.  
  386. STATIC LONG
  387. WritePrefs( const STRPTR file, const STRPTR *patterns, const BOOL remap )
  388. {
  389.     struct IFFHandle    *iff;
  390.     LONG    rc = IFFERR_NOMEM;
  391.  
  392.     if( iff = AllocIFF() )
  393.     {
  394.         if( iff->iff_Stream = Open( file, MODE_NEWFILE ) )
  395.         {
  396.             InitIFFasDOS( iff );
  397.  
  398.             if( !( rc = OpenIFF( iff, IFFF_WRITE ) ) )
  399.             {
  400.                 rc = WriteWBPatternPrefs( iff, patterns, remap );
  401.                 CloseIFF( iff );
  402.             } /* if */
  403.  
  404.             if( !Close( iff->iff_Stream ) )
  405.             {
  406.                 rc = FALSE;
  407.             } /* if */
  408.         }
  409.         else
  410.         {
  411.             rc = IFFERR_NOFILE;
  412.         } /* if */
  413.  
  414.         FreeIFF( iff );
  415.     } /* if */
  416.  
  417.     return( rc );
  418. } /* WritePrefs */
  419.  
  420.  
  421. STATIC LONG
  422. ShowWBPatternPrefs( struct IFFHandle *iff )
  423. {
  424.     struct CollectionItem    *ci = NULL;
  425.     LONG    rc;
  426.  
  427.     /* Load and store all PTRN chunks */
  428.     IFF( CollectionChunk( iff, ID_PREF, ID_PTRN ) );
  429.  
  430.     /* Stop before leaving PREF chunk, so we can process the stored PTRN chunks. */
  431.     IFF( StopOnExit( iff, ID_PREF, ID_FORM ) );
  432.  
  433.     /* Read the stuff */
  434.     rc = ParseIFF( iff, IFFPARSE_SCAN );
  435.  
  436.     if( rc == IFFERR_EOC )
  437.     {
  438.         /* Get the last loaded chunk */
  439.         ci = FindCollection( iff, ID_PREF, ID_PTRN );
  440.         rc = 0;
  441.     } /* if */
  442.  
  443.     /* Process all chunks */
  444.     while( ci )
  445.     {
  446.         const STATIC STRPTR
  447.         Types[] =
  448.         {
  449.             "Workbench", "Window   ", "Screen   "
  450.         }; /* Types[] */
  451.         struct WBPatternPrefs    *chunk;
  452.         STRPTR    type;
  453.  
  454.         chunk = ( struct WBPatternPrefs * ) ci->ci_Data;
  455.         type = Types[ chunk->wbp_Which ];
  456.  
  457.         if( ci->ci_Size < sizeof( struct WBPatternPrefs ) )
  458.         {
  459.             Printf( "%s pattern chunk is too small (%ld bytes)\n", type, ci->ci_Size );
  460.         }
  461.         else if( chunk->wbp_Flags & WBPF_PATTERN )
  462.         {
  463.             Printf( "%s pattern is not a picture\n", type );
  464.         }
  465.         else if( !chunk->wbp_DataLength )
  466.         {
  467.             Printf( "%s picture: Empty name\n", type );
  468.         }
  469.         else
  470.         {
  471.             LONG    len;
  472.  
  473.             /* Make sure we only print the string... */
  474.             len = strlen( ( STRPTR ) ( chunk + 1 ) );
  475.             len = MIN( len, chunk->wbp_DataLength );
  476.  
  477.             /* Name data is stored after the WBPatternPrefs structure */
  478.             Printf( "%s picture: ", type );
  479.             FWrite( Output(), chunk + 1, len, 1 );
  480.             PutStr( "\n" );
  481.         } /* if */
  482.  
  483.         ci = ci->ci_Next;
  484.     } /* while */
  485.  
  486.     return( rc );
  487. } /* ShowWBPatternPrefs */
  488.  
  489.  
  490. STATIC LONG
  491. ShowPrefs( const STRPTR file )
  492. {
  493.     struct IFFHandle    *iff;
  494.     LONG    rc = IFFERR_NOMEM;
  495.  
  496.     if( iff = AllocIFF() )
  497.     {
  498.         if( iff->iff_Stream = Open( file, MODE_OLDFILE ) )
  499.         {
  500.             InitIFFasDOS( iff );
  501.  
  502.             if( !( rc = OpenIFF( iff, IFFF_READ ) ) )
  503.             {
  504.                 rc = ShowWBPatternPrefs( iff );
  505.                 CloseIFF( iff );
  506.             } /* if */
  507.  
  508.             Close( iff->iff_Stream );
  509.         }
  510.         else
  511.         {
  512.             rc = IFFERR_NOFILE;
  513.         } /* if */
  514.  
  515.         FreeIFF( iff );
  516.     } /* if */
  517.  
  518.     return( rc );
  519. } /* ShowPrefs */
  520.  
  521.  
  522. /******************** Main ********************/
  523.  
  524.  
  525. struct Args
  526. {
  527.     STRPTR    Workbench;
  528.     STRPTR    Window;
  529.     STRPTR    Screen;
  530.     STRPTR    File;
  531.     LONG    NoRemap;
  532.     LONG    Show;
  533. }; /* struct Args */
  534.  
  535. #define TEMPLATE    "WORKBENCH,WINDOW,SCREEN,FILE/K,NOREMAP/S,SHOW/S"
  536.  
  537.  
  538. STATIC STRPTR
  539. GetPattern( STRPTR dir )
  540. {
  541.     struct Node    *node = NULL;
  542.     STRPTR    rc = NULL;
  543.     LONG    i;
  544.  
  545.     if( dir && !IoErr() )
  546.     {
  547.         if( !( node = GetRandomFile( dir ) ) )
  548.         {
  549.             i = IoErr();
  550.             Printf( "RndPat: Error scanning drawer \"%s\":\n", dir );
  551.             PrintFault( i, NULL );
  552.         }
  553.         else if( rc = AllocVec( i = strlen( dir ) + strlen( node->ln_Name ) + 2, MEMF_PUBLIC ) )
  554.         {
  555.             strcpy( rc, dir );
  556.             AddPart( rc, node->ln_Name, i );
  557.             SetIoErr( 0 );
  558.         }
  559.         else
  560.         {
  561.             PutStr( "RndPat: Not enough memory\n" );
  562.             SetIoErr( ERROR_NO_FREE_STORE );
  563.         } /* if */
  564.     } /* if */
  565.  
  566.     FreeVec( node );
  567.     return( rc );
  568. } /* GetPattern */
  569.  
  570.  
  571. STATIC LONG
  572. Main( VOID )
  573. {
  574.     struct RDArgs    *rda;
  575.     struct Args    args;
  576.     LONG    rc = RETURN_ERROR, err;
  577.  
  578.     memset( &args, 0, sizeof( args ) );
  579.     args.File = "Env:sys/wbpattern.prefs";
  580.  
  581.     if( rda = ReadArgs( TEMPLATE, ( LONG * ) &args, NULL ) )
  582.     {
  583.         if( args.Show )
  584.         {
  585.             if( err = ShowPrefs( args.File ) )
  586.             {
  587.                 Printf( "RndPat: Couldn't show \"%s\":\n%s\n", args.File, IffError( err ) );
  588.             }
  589.             else
  590.             {
  591.                 rc = RETURN_OK;
  592.             } /* if */
  593.         }
  594.         else
  595.         {
  596.             InitSeed();
  597.             SetIoErr( 0 );
  598.  
  599.             if( args.Screen || args.Workbench || args.Window )
  600.             {
  601.                 STRPTR    patterns[ 3 ];
  602.  
  603.                 patterns[ 0 ] = GetPattern( args.Workbench );
  604.                 patterns[ 1 ] = GetPattern( args.Window    );
  605.                 patterns[ 2 ] = GetPattern( args.Screen    );
  606.  
  607.                 if( !IoErr() )
  608.                 {
  609.                     if( err = WritePrefs( args.File, patterns, ( BOOL ) args.NoRemap ) )
  610.                     {
  611.                         Printf( "RndPat: Couldn't create \"%s\":\n%s\n", args.File, IffError( err ) );
  612.                     }
  613.                     else
  614.                     {
  615.                         rc = RETURN_OK;
  616.                     } /* if */
  617.                 } /* if */
  618.  
  619.                 FreeVec( patterns[ 0 ] );
  620.                 FreeVec( patterns[ 1 ] );
  621.                 FreeVec( patterns[ 2 ] );
  622.             }
  623.             else
  624.             {
  625.                 PutStr( "RndPat: No pattern(s) specified\n" );
  626.                 rc = RETURN_WARN;
  627.             } /* if */
  628.         } /* if */
  629.  
  630.         FreeArgs( rda );
  631.     } /* if */
  632.  
  633.     return( rc );
  634. } /* Main */
  635.